# -*- codeing = utf-8 -*-
# @Time : 2022/10/22 11:57
# @Author : ZN
# @Email : 747723508@qq.com
# @File : serializers.py
# @Software: PyCharm
from datetime import datetime
from decimal import Decimal
from random import randint

from django.db import transaction
from rest_framework import serializers
from rest_framework.fields import SerializerMethodField
from rest_framework.serializers import ModelSerializer

from users.models import Address
from .models import *


class ClassificationSerializer(ModelSerializer):
    class Meta:
        model = Classification
        fields = ['id', 'name']


class ParentClassificationSerializer(ModelSerializer):
    classification_set = ClassificationSerializer(many=True, read_only=True)

    class Meta:
        model = Classification
        fields = ['id', 'name', 'classification_set', 'parent']

        extra_kwargs = {
            'parent': {'write_only': True}
        }


class CommodityImgSerializer(ModelSerializer):
    class Meta:
        model = CommodityImg
        fields = ['src']


class CommoditySerializer(ModelSerializer):
    classification1_name = serializers.CharField(source='classification1.name', read_only=True)
    classification2_name = serializers.CharField(source='classification2.name', read_only=True)
    commodityimg_set = CommodityImgSerializer(many=True, read_only=True)

    class Meta:
        model = Commodity
        exclude = ['is_delete']


class ShoppingCartSerializer(ModelSerializer):
    commodityDetail = SerializerMethodField()

    class Meta:
        model = ShoppingCart
        fields = '__all__'

    def validate(self, data):  # 校验购物车输入的数量 对比数据库中库存
        if data['number'] <= 0:
            raise serializers.ValidationError('您输入的商品数量有误')
        elif data['number'] > data['commodity'].stock:
            raise serializers.ValidationError('您输入的商品数量超出库存')
        else:
            return data

    def get_commodityDetail(self, shoppingcart):
        return CommoditySerializer(shoppingcart.commodity).data


class OrderSerializer(ModelSerializer):
    cart = serializers.ListField(write_only=True)  # 返回前端返回的购物车的商品信息

    class Meta:
        model = Order
        fields = '__all__'
        read_only_fields = ['order_id', 'total_count', 'total_amount', 'status', 'user']

    def create(self, validated_data):
        # 自定义创建订单功能

        # 生成订单号码 唯一性，标识性。20221029193152(时间年月日时分秒)+000001（6位数用户id）+12（2位随机数） 22位
        user = self.context['request'].user
        order_id = datetime.now().strftime('%Y%m%d%H%M%S') + '%06d%02d' % (user.id, randint(1, 99))
        # 获取前端传入的支付方式
        pay_method = validated_data.get('pay_method')
        # 获取前端传入的收货地址
        try:
            address = Address.objects.get(id=validated_data.get('address'))  # 得到的id值 需要转换
        except Address.DoesNotExist:
            raise serializers.ValidationError('address error')
        # 格式化收获地址 内蒙古呼和浩特市赛罕区玖都公馆7#1606[张宁 收] 12345678901
        address_s = f'{address.province.name}{address.city.name}{address.district.name}{address.place}[{address.receiver}收]{address.mobile}'
        with transaction.atomic():
            # 开启事务，在with所以中的代码执行完毕后自动关闭事务 with上下文协议
            # 里面的代码都在一个原子中，事务中
            # 创建订单信息
            save_point = transaction.savepoint()  # 创建保存点，事务没有执行完毕后回滚的地方
            try:
                order = Order.objects.create(
                    order_id=order_id,
                    total_count=0,
                    total_amount=Decimal('0.00'),
                    pay_method=pay_method,
                    status=1 if pay_method == 1 else 2,
                    user=user,
                    address=address_s
                )

                # 获取到购物车中要结算的商品
                carts = validated_data.get('cart')
                # 遍历id，判断前端传入的商品信息是否存在
                for cart_id in carts:
                    while True:
                        try:
                            cart = ShoppingCart.objects.get(id=cart_id)
                        except ShoppingCart.DoesNotExist:
                            transaction.savepoint_rollback(save_point)  # 出现异常后回滚到保存点
                            raise serializers.ValidationError('购物信息不存在')

                        # 得到购物车中的商品信息，库存数量，销量
                        commodity = cart.commodity
                        # 原本的库存以及销量
                        origin_stock = commodity.stock
                        origin_sale = commodity.sales

                        # 核算 购买的数量是否超过库存
                        if cart.number > origin_stock:
                            raise serializers.ValidationError('库存不足')

                        # 购买数量正确继续执行 库存操作：减少库存，增加销量
                        new_stock = origin_stock - cart.number
                        new_sale = origin_sale - cart.number

                        # 更新
                        # 更新库存以及销量信息,模型对象修改属性使用save保存，查询集使用update get-模型对象-save filter-查询集-update
                        res = Commodity.objects.filter(id=commodity.id, stock=origin_stock).update(stock=new_stock,
                                                                                                   sales=new_sale)
                        if not res:
                            continue  # 如果res条件不成立，也就是not false（为真），则执行缩进代码continue跳出到while True，重新获取购物车信息，以及库存信息，再次判断，如果res条件为真，也就是not True（为假），则不执行缩进代码continue，继续往下面执行
                        # 创建订单对应的商品数据
                        OrderGoods.objects.create(
                            number=cart.number,
                            price=commodity.price,
                            order=order,
                            commodity=commodity
                        )

                        # 更新订单表
                        order.total_count += cart.number
                        order.total_amount += (cart.number * commodity.price)

                        break
                # 保存订单信息
                order.save()
                # 清除
                ShoppingCart.objects.filter(id__in=carts).delete()
            except Exception as e:
                transaction.savepoint_rollback(save_point)
                raise serializers.ValidationError(e)
            else:
                transaction.savepoint_commit(save_point)
        return order

class PaymentSerializer(ModelSerializer):
    class Meta:
        model = Payment
        fields = '__all__'